package de.gameduell.framework.gui.animation {
	import fl.transitions.TweenEvent;

	import de.gameduell.framework.gui.animation.TweenManager;
	import de.gameduell.framework.gui.animation.Tweenable;
	import de.gameduell.framework.util.SingleSyncTimer;
	import de.gameduell.framework.util.SyncTimer;

	import flash.events.EventDispatcher;
	import flash.events.TimerEvent;

	public class SyncTween extends EventDispatcher implements Tweenable {

		protected var _syncTimer:SyncTimer;
		protected var _startValue:Number;
		protected var _endValue:Number;
		protected var _duration:Number;
		protected var _tweenedObject:Object;
		protected var _property:String;
		protected var _currentValue:Number;
		protected var _distance:Number;
		protected var _isPlaying:Boolean;
		protected var _function:Function;
		protected var _passedTime:Number;

		/**
		 * 
		 */
		public function SyncTween(tweenedObject:Object, property:String, easeType:Function, startValue:Number, endValue:Number, duration:Number) {
			_syncTimer = SingleSyncTimer.getInstance();
			_tweenedObject = tweenedObject;
			if(	_tweenedObject.hasOwnProperty(property) ) {
				_property = property;
			} else {
				var error:Error = new Error("Tween object doesn't contain property: " + _property);
				throw(error);
			}
			_startValue = startValue;
			_currentValue = startValue;
			_endValue = endValue;
			_duration = duration * 1000;

			_function = easeType;
			_passedTime = 0;

			_distance = _endValue - _startValue;
			_isPlaying = false;
			
			TweenManager.getInstance().add(this);
		}

		public function get isPlaying():Boolean {
			return _isPlaying;
		}

		/**
		 * starts the tween
		 */
		public function start():void {
			_isPlaying = true;
			_syncTimer.addEventListener(TimerEvent.TIMER, timerHandler);		
		}

		public function stop():void {
			_isPlaying = false;
			_syncTimer.removeEventListener(TimerEvent.TIMER, timerHandler);
		}

		public function continueTo(targetValue:Object, duration:Number = 0):void {
			_endValue = Number(targetValue);
			_startValue = _currentValue;
			_distance = _endValue - _startValue;
			if(duration != 0) {
				_duration = duration * 1000;
			}
			_passedTime = 0;
			
			if( _isPlaying == false ) {
				start();
			}
		}

		protected function update(passedTime:int):void {
			if( isNaN(_endValue) == false && _passedTime != _duration ) {
				_passedTime += passedTime;
				if(_passedTime > _duration) {
					_passedTime = _duration;
				}
				_currentValue = _function(_passedTime, _startValue, _distance, _duration);				
				_tweenedObject[_property] = _currentValue;
			} else {
				motionFinished();
			}
		}	

		protected function timerHandler(event:TimerEvent):void {
			update(_syncTimer.passedTime);
		}

		protected function motionFinished():void {
			stop();
			var event:TweenEvent = new TweenEvent(TweenEvent.MOTION_FINISH, 0, 0);
			dispatchEvent(event);
		}

		public function get endValue():Number {
			return _endValue;
		}

		public function get passedTime():Number {
			return _passedTime;
		}

		public function get tweenedObject():Object {
			return _tweenedObject;
		}

		public function get duration():Number {
			return _duration;
		}

		public function set func(func:Function):void {
			_function = func;
		}
	}
}